#include<iostream>
#include<pthread.h>
#include<string>
#include<vector>
#include<time.h>
#include<unistd.h>


const int NUM=5; //创建的线程数量
int ticket=10000; //票数

class threadLock
{//我们将锁的id和锁姓名封装成一个类
public:
    std::string _name; // 给程序员识别的
    pthread_mutex_t* _lock; //让不同的线程使用的锁
public:
    threadLock(int num,pthread_mutex_t* Lock)
    :_lock(Lock)
    {
        _name="Thread"+std::to_string(num);
    }
};

void* getTicket(void* args)
{
    //获取锁名和id
	threadLock *td = static_cast<threadLock*>(args);		    
	while(1){ //循环抢票
        //上锁 每一次我们将要访问下面这段代码时，除了当前线程，禁止其它线程访问
        pthread_mutex_lock(td->_lock);
		if(ticket > 0){//有票 
			usleep(1000);     // 模拟抢票的时间
			 printf("%s is running, get a ticket: %d\n", td->_name.c_str(), ticket);
			ticket--;
            pthread_mutex_unlock(td->_lock); //关锁
            usleep(10);
		}
		else{ //无票 关锁 退出
           pthread_mutex_unlock(td->_lock);
           break;
        }

        //pthread_mutex_unlock(td->_lock); //在这里不如上面分两端写，两端写锁占用的资源更少
	}
    std::cout << td->_name.c_str() << "` quit!" << std::endl;
	return nullptr;
}

int main(){

    pthread_mutex_t lock; //定义一把锁
    pthread_mutex_init(&lock,nullptr); //进行锁的初始化

	std::vector<pthread_t> tids; //线程编号数组 这两组是为了方便释放
	std::vector<threadLock*> thread_locks; //锁编号数组
    
    for(int i=0;i<=NUM;i++){ //循环创建线程，进行抢票
        
        threadLock* td=new threadLock(i,&lock); //创建一个新锁
        pthread_t tid; 
        pthread_create(&tid, nullptr, getTicket, td);//创建线程 同时抢票
        //让线程和锁进入不同的数组
        tids.push_back(tid);
		thread_locks.push_back(td);
    }
     
     //循环释放
     for(auto e : tids){
      pthread_join(e, nullptr);
     }
				
				
	for(auto td : thread_locks){
        delete td;
     }
				       
    //删除锁
    pthread_mutex_destroy(&lock);
	return 0;
}
